package com.example.demokotlin

import org.junit.Test


/**
 * 函数式编程
 * 3) 合并zip/fold
 * 合并函数将不同的集合合并成为一个新集合
 *
 *
 * @author zhouronghua
 * @time 2021/9/22 5:22 下午
 */
class CombineTest {

    /**
     * 计算集合统计
     * min() 与 max() 分别返回最小和最大的元素；
     * average() 返回数字集合中元素的平均值；
     * sum() 返回数字集合中元素的总和；
     * count() 返回集合中元素的数量；
     * sumBy() 使用对集合元素调用返回 Int 值的函数。
     * sumByDouble() 与返回 Double 的函数一起使用。
     *
     * @author zhouronghua
     * @time 2021/9/22 6:17 下午
     */
    @Test
    fun testStatistics() {
        println("=== 集合元素统计使用 ===")
        val numbers = listOf(6, 42, 10, 4)
        println("Count: ${numbers.count()}")
        println("Max: ${numbers.maxOrNull()}")
        println("Min: ${numbers.minOrNull()}")
        println("Average: ${numbers.average()}")
        println("Sum: ${numbers.sum()}")
    }

    /**
     * zip合并函数合并两个集合，返回一个包含键值对的集合
     *
     * @author zhouronghua
     * @time 2021/9/22 5:46 下午
     */
    @Test
    fun testZip() {
        println("=== zip将两个列表合并为键值对列表 ===")
        val animals = listOf("cat", "bear", "tiger")
        val colors = listOf("black", "gray", "yellow", "red")
        // 返回List<Pair>
        val animalMap = animals.zip(colors)
        println(animalMap)
    }

    /**
     * 有函数 reduce() 和 fold()，它们依次将所提供的操作应用于集合元素并返回累积的结果。
     * 操作有两个参数：先前的累积值和集合元素。
     * 区别：
     * fold() 接受一个初始值并将其用作第一步的累积值，
     * reduce() 的第一步则将第一个元素值作为初始累计值，然后计算累计值。
     *
     * @author zhouronghua
     * @time 2021/9/22 5:57 下午
     */
    @Test
    fun testFold() {
        println("=== reduce计算累加值（第一个元素作为初始值） ===")
        val numbers = listOf(5, 2, 10, 4)
        // sum初始值为5
        // 第一轮： sum: 5+2=7 [10, 4]
        // 第二轮：sum:  7 + 10 = 17 [4]
        // 第三轮：sum: 17+ 4 = 21
        val sum = numbers.reduce { sum, element -> sum + element }
        println(sum)
        // 计算2倍和(sum初始值为5)
        // 第一轮： sum: 5+2 * 2 =9 [10, 4]
        // 第二轮：sum:  9 + 10 * 2 = 29 [4]
        // 第三轮：sum: 29+ 4 * 2 = 37
        val sum2 = numbers.reduce { sum, element -> sum + element * 2 }
        println(sum2)
        println("=== fold计算累加值（指定初始值） ===")
        // sum初始值0
        // 第一轮：sum: 0 + 5*2=10         [2, 10, 4]
        // 第二轮：sum: 10 + 2*2=14       [10, 4]
        // 第三轮：sum: 14 + 10*2=34     [4]
        // 第四轮：sum: 34 + 4*2 = 42
        val sumDoubled = numbers.fold(0) { sum, element -> sum + element * 2 }
        println(sumDoubled)
    }
}